// ble相关操作
var debug = require('./debug.js');

const app = getApp();

const BLE_MODULE_NAME = "ble";

const BLE_MTU_SIZE = 180; // 最大MTU大小

var bleInitFlag = false; // ble是否初始化
/**
 * 连接的设备列表，每一次新设备调用连接就会把该设备加入到这个列表中，连接成功或者正在连接的设备会在这个表中，其他设备表示未连接，这样做是为了防止用户重复连接同一个设备，在android平台上会有问题
 * 数据结构：
 * {
 *  devId: id,
 *  devStatus: status,  // 0 连接成功，1正在连接
 *  devCb: {}, //连接状态回调,参数1设备ID，参数2连接状态
 * }
 */
const BLE_CON_MAX_NUM = 3; // 最大同时连接个数

const BLE_CON_SUCCESS = 0;  // 连接成功
const BLE_CON_ING = 1;  // 正在连接
const BLE_CON_FAIL = 2; // 连接失败

var bleConDevArr = []; 

/**
 * @功能: ble初始化
 * @参数：
 *  cb[in]: 初始化结果状态回调， true表示初始化成功
 * @返回：
 * @备注: 初始化之前请检查一下是否有蓝牙权限
 */
function Init(cb) {
    if (bleInitFlag) {
        // 防止重复初始化
        if (typeof cb == 'function') {
            cb(true);
        }

        return;
    }

    // 初始化蓝牙模块
    wx.openBluetoothAdapter({
        mode: 'central',
        success: (res) => {
            debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"初始化蓝牙模块成功！");
            bleInitFlag = true;
            if (typeof cb == 'function') {
                cb(true);
            }
        },
        fail: (res) => {
            debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"初始化蓝牙模块失败！");
            bleInitFlag = false;
            if (typeof cb == 'function') {
                cb(false);
            }
        }
      });
    
      // 蓝牙适配器状态监听
      wx.onBluetoothAdapterStateChange((res) => {
        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"蓝牙适配器状态改变", res.available);
        bleInitFlag = res.available;
      });

      // 设备连接状态监听回调
      wx.onBLEConnectionStateChange(function(res) {
        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG, `device ${res.deviceId} state has changed, connected: ${res.connected}`)
        
        // 在连接数组里面查找该设备是否已经处理正在连接或者连接成功的状态
        var index = findDevIndexInArrByDevId(res.deviceId);

        if (index >= 0) {
            if (res.connected) {
                bleConDevArr[index].devStatus = BLE_CON_SUCCESS; // 连接成功，更改设备状态

                // 连接成功，设置MTU
                wx.setBLEMTU({
                    deviceId: res.deviceId,//蓝牙设备ID
                    BLE_MTU_SIZE,
                    success:(res)=>{
                        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"setBLEMTU success")
                    },
                    fail:(res)=>{
                        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"setBLEMTU fail")
                    }
                })

                if (typeof bleConDevArr[index].devCb == "function") {
                    bleConDevArr[index].devCb(bleConDevArr[index].devId, BLE_CON_SUCCESS);
                }
            } else {
                if (typeof bleConDevArr[index].devCb == "function") {
                    bleConDevArr[index].devCb(bleConDevArr[index].devId, BLE_CON_FAIL);
                }

                debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"设备断开，删除设备", bleConDevArr[index].devId);
                bleConDevArr.splice(index, 1); // 断开连接，直接从数组中删除
            }
        }
      });
}

/**
 * @功能: 页面释放的时候调用
 * @参数：
 *  cb[in]: 关闭蓝牙回调失败成功回调
 * @返回：
 */
function DeInit(cb) {
    // if (!bleInitFlag) {
    //     return;
    // }

    // 如果当前设备列表中还有连接的设备，那么就先去全部断开
    for (var i=0; i<bleConDevArr.length; i++) {
        wx.closeBLEConnection({
          deviceId: bleConDevArr[i].deviceId
        });
    }

    // 关闭蓝牙连接状态监听回调
    wx.offBLEConnectionStateChange();
    bleConDevArr.slice(0, bleConDevArr.length); // 清空设备列表数组

    wx.closeBluetoothAdapter({
      success: (res) => {
        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"关闭蓝牙适配器成功");
          if (typeof cb == 'function') {
            cb(true);
        }
      },
      fail: (res) => {
        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"关闭蓝牙适配器失败");
         if (typeof cb == 'function') {
            cb(false);
        }
      },
    });

    // 关闭蓝牙适配器状态监听
    wx.offBluetoothAdapterStateChange();

    bleInitFlag = false;
}

/**
 * @功能: 获取BLE状态
 * @参数：
 * @返回：true表示可用状态，false表示不可用
 */
function getBleStatus() {
    return bleInitFlag;
}

/**
 * @功能: 开始搜索
 * @参数：
 *  cb[in]: 搜索到设备的回调函数
 * @返回：
 */
function StartDiscovery(cb) {
    if (!bleInitFlag) {
        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"搜索失败，BLE未初始化");
        return
    }

    // 开始搜索附近的蓝牙外围设备
    wx.startBluetoothDevicesDiscovery({
        allowDuplicatesKey: true //允许重复上报设备，主要是为了统计信号强度
    })

    // 监听扫描到新设备事件
    wx.onBluetoothDeviceFound((res) => {
        if (typeof cb == 'function') {
            cb(res);
        }
    });
}

/**
 * @功能: 停止搜索
 * @参数：
 * @返回：
 */
function StopDiscovery() {
    if (!bleInitFlag) {
        return;
    }

    wx.stopBluetoothDevicesDiscovery();
}

/**
 * 连接指定的设备
 * @param {string} deviceId 蓝牙设备ID
 * @param {function} cb 连接状态回调，参数1为设备id，参数2连接状态
 */
function connect(deviceId, timeout, cb) {
    if (!bleInitFlag || bleConDevArr.length>BLE_CON_MAX_NUM) {
        if (typeof cb == "function") {
            cb(deviceId, BLE_CON_FAIL);
        }
    }

    // 在连接数组里面查找该设备是否已经处理正在连接或者连接成功的状态
    var index = findDevIndexInArrByDevId(deviceId);

    if (index >= 0) {  // 如果在列表中存在，判断该设备状态
        if (bleConDevArr[index].devStatus == BLE_CON_SUCCESS) { // 连接成功状态
            if (typeof cb == "function") {
                cb(deviceId, BLE_CON_SUCCESS);
            }
        } else {    // 正在连接状态，直接返回重复连接
            console.log("重复连接", deviceId);
            if (typeof cb == "function") {
                cb(deviceId, BLE_CON_ING);
            }
        }
    } else { // 创建一个新连接
        bleConDevArr.push({
            devId: deviceId,
            devStatus: BLE_CON_ING,
            devCb: cb
        });

        wx.createBLEConnection({
            deviceId, // 搜索到设备的 deviceId
            timeout: timeout,
            success: () => { 
                // 不在这里处理连接成功回调事件，在状态改变里面处理，等状态回调回来才算真正连接成功
                // if (typeof cb == "function") {
                //     cb(deviceId, BLE_CON_SUCCESS);
                // }
            },
            fail: () => {
                if (typeof cb == "function") {
                    cb(deviceId, BLE_CON_FAIL);
                    debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"连接失败", deviceId);

                    // 连接失败删除设备
                    // 在连接数组里面查找该设备是否已经处理正在连接或者连接成功的状态
                    var index1 = findDevIndexInArrByDevId(deviceId);
                    if (index1 >= 0) {
                        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"连接失败，删除设备", bleConDevArr[index1].devId);
                        bleConDevArr.splice(index1, 1); 
                    }
                }
            }
        });
    }
}

/**
 * 主动断开某个设备的连接
 */
function disconnect(deviceId, cb) {
    // 在连接数组里面查找该设备是否已经处于正在连接或者连接成功的状态
    var index = findDevIndexInArrByDevId(deviceId);

    if (index >= 0) {
        // 不在这里做设备删除操作，在状态回调里面去做，防止断开连接失败，但是有提前把设备删除了，那么这个资源就没有办法释放了
        // bleConDevArr.splice(index, 1); // 从数组中删除

        debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"断开设备", deviceId);
        if (typeof cb == "function") {
            wx.closeBLEConnection({
                deviceId,
                success: (res) => { // 成功回调
                    cb(true);
                },
                fail: (res) => { // 失败回调
                    cb(false);
                }
            });
        } else {
            wx.closeBLEConnection({deviceId});
        }
    } else {
        if (typeof cb == "function") {
            cb(false);
        }
    }
}

/**
 * 获取设备的连接状态
 * @param {string} deviceId 
 */
function getDevConStaus(deviceId) {
    // 在连接数组里面查找该设备是否已经处于正在连接或者连接成功的状态
    var index = findDevIndexInArrByDevId(deviceId);

    if (index >= 0) {
        return bleConDevArr[index].devStatus;
    } else {
        return BLE_CON_FAIL;
    }
}

/**
 * 获取service
 * @param {string} deviceId 
 * @param {function} cb 成功返回服务列表，失败参数为null
 */
function getDevServices(deviceId, cb) {
    if (!bleInitFlag) {
        if (typeof cb == "function") {
            cb(null);
        }
        return;
    }
    
    // 设备没有连接过
    let index  = findDevIndexInArrByDevId(deviceId);
    if (index < 0) {
        if (typeof cb == "function") {
            cb(null);
        }
        return;
    }

    // 判断该设备是否为连接成功状态
    if (bleConDevArr[index].devStatus != BLE_CON_SUCCESS) {
        if (typeof cb == "function") {
            cb(null);
        }
        return;
    }

    wx.getBLEDeviceServices({
        deviceId,
        success: (res) => {
            debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,'device services:', res.services);
          if (typeof cb == "function") {
              cb(res);
          }
        },
        fail: (res) => {
            if (typeof cb == "function") {
                cb(null);
            }
        }
    });
}

/**
 * 获取特征值列表
 * @param {string} deviceId 
 * @param {string} serviceId 
 * @param {function} cb 成功返回特征值列表，失败返回null
 */
function getDevChars(deviceId, serviceId, cb) {
    if (!bleInitFlag) {
        if (typeof cb == "function") {
            cb(null);
        }
        return;
    }
    
    // 设备没有连接过
    let index  = findDevIndexInArrByDevId(deviceId);
    if (index < 0) {
        if (typeof cb == "function") {
            cb(null);
        }
        return;
    }

    // 判断该设备是否为连接成功状态
    if (bleConDevArr[index].devStatus != BLE_CON_SUCCESS) {
        if (typeof cb == "function") {
            cb(null);
        }
        return;
    }

    wx.getBLEDeviceCharacteristics({
        deviceId,
        // 这里的 serviceId 需要在 wx.getBLEDeviceServices 接口中获取
        serviceId,
        success: (res) => {
            debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,'device getBLEDeviceCharacteristics:', res.characteristics)
            // console.log("getBLEDeviceCharacteristics", res);
            if (typeof cb == "function") {
                cb(res);
            }
        },
        fail: (res) => {
            if (typeof cb == "function") {
                cb(null);
            }
        }
    });
}

/**
 * 写特征值
 * @param {string} devId 
 * @param {string} serId 
 * @param {string} charId 
 * @param {ArrayBuffer} writeValue 
 * @param {function} cb 参数1成功标志：true为成功, 参数2错误码
 */
function writeDevCharValue(devId, serId, charId, writeValue, cb) {
    if (!bleInitFlag) {
        if (typeof cb == "function") {
            cb(false, 10000);
        }
        return;
    }
    
    // 设备没有连接过
    let index  = findDevIndexInArrByDevId(devId);
    if (index < 0) {
        if (typeof cb == "function") {
            cb(false, 10006);
        }
        return;
    }

    // 判断该设备是否为连接成功状态
    if (bleConDevArr[index].devStatus != BLE_CON_SUCCESS) {
        if (typeof cb == "function") {
            cb(false, 10006);
        }
        return;
    }

    if (writeValue.byteLength == 0) {
        if (typeof cb == "function") {
            cb(false, 10013);
        }
        return;
    }

    debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"发送数据", devId, serId, charId);

    // 如果数据长度超过20，需要做分包发送处理才行
    let srcArrayBuffer = new Uint8Array(writeValue);
    let haveBeenSendNum = 0; // 累计已经发送的字节数

    do {
        let revSendNum = srcArrayBuffer.length-haveBeenSendNum; // 剩余的发送字节数
        let currSendNumTmp = 0; // 本次需要发送的字节数

        if (revSendNum >= BLE_MTU_SIZE) {
            currSendNumTmp = BLE_MTU_SIZE;
        } else {
            currSendNumTmp = revSendNum;
        }

        let sendArrayBuffer = new ArrayBuffer(currSendNumTmp);
        let uint8ArrayBuffer = new Uint8Array(sendArrayBuffer);

        for (let i=0; i<currSendNumTmp; i++) {
            uint8ArrayBuffer[i] = srcArrayBuffer[haveBeenSendNum];
            haveBeenSendNum++;
        }

        let haveBeenSendNumTmp = haveBeenSendNum; // 需要用一个局部变量记录一下当前已经发送的数据个数，不能用全局的，由于发送是异步的，所以当发送成功返回的时候，全局的haveBeenSendNum早就已经等于srcArrayBuffer.length，导致多次抛发送成功的消息
        wx.writeBLECharacteristicValue({
            // 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
            deviceId: devId,
            // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
            serviceId: serId,
            // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
            characteristicId: charId,
            // 这里的value是ArrayBuffer类型
            value: sendArrayBuffer,
            success: (res) => {
                // 这里要做到所有数据发送成功才返回成功回调
                if (haveBeenSendNumTmp >= srcArrayBuffer.length) {
                    if (typeof cb == "function") {
                        cb(true, 0);
                    }
                }
            },
            fail: (res) => {
                if (typeof cb == "function") {
                    cb(false, res.errCode);
                }
                debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG, "writeBLECharacteristicValue 失败", res.errCode, res.errMsg);
                return;
            }
        });
    } while(haveBeenSendNum < srcArrayBuffer.length);
}

/**
 * 读取一次特征值
 * @param {string} devId 
 * @param {string} serId 
 * @param {string} charId 
 * @param {function} cb 参数1：读取失败成功标志，参数2：错误码
 */
function readDevCharValue(devId, serId, charId, cb) {
    if (!bleInitFlag) {
        if (typeof cb == "function") {
            cb(false, 10000);
        }
        return;
    }
    
    // 设备没有连接过
    let index  = findDevIndexInArrByDevId(devId);
    if (index < 0) {
        if (typeof cb == "function") {
            cb(false, 10006);
        }
        return;
    }

    // 判断该设备是否为连接成功状态
    if (bleConDevArr[index].devStatus != BLE_CON_SUCCESS) {
        if (typeof cb == "function") {
            cb(false, 10006);
        }
        return;
    }

    wx.readBLECharacteristicValue({
        deviceId: devId,
        serviceId: serId,
        characteristicId: charId,
        success (res) {
            if (typeof cb == "function") {
                cb(true, res.errCode);
            }
        },
        fail (res) {
            if (typeof cb == "function") {
                cb(false, res.errCode);
            }
            debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG, "readBLECharacteristicValue 失败", res.errCode, res.errMsg);
        }
    });   
}

/**
 * 打开特征值数值改变回调
 * @param {function} cb 
 */
function onDevCharValueChange(cb) {
    wx.onBLECharacteristicValueChange(cb);
}

/**
 * 关闭特征值数值改变回调
 * @param {function} cb 
 */
function offDevCharValueChange(cb) {
    wx.offBLECharacteristicValueChange(cb);
}

/**
 * 是否启用特征值notify功能
 * @param {string} devId 
 * @param {string} serId 
 * @param {string} charId 
 * @param {boolean} status 
 */
function enableDevCharNotify(devId, serId, charId, status) {
    if (!bleInitFlag) {
        return;
    }
    
    // 设备没有连接过
    let index  = findDevIndexInArrByDevId(devId);
    if (index < 0) {
        return;
    }

    // 判断该设备是否为连接成功状态
    if (bleConDevArr[index].devStatus != BLE_CON_SUCCESS) {
        return;
    }

    wx.notifyBLECharacteristicValueChange({
        deviceId: devId,
        serviceId: serId,
        characteristicId: charId,
        state: status,
    });
}

function findDevIndexInArrByDevId(deviceId) {
    var index = 0;
    for (index=0; index<bleConDevArr.length; index++) {
        if (deviceId == bleConDevArr[index].devId) {
            break;
        }
    }

    if (index != bleConDevArr.length) {
        return index;
    } else {
        return -1;
    }
}

module.exports = {
    BLE_CON_SUCCESS,
    BLE_CON_ING,
    BLE_CON_FAIL,

    Init,
    DeInit,
    StartDiscovery,
    StopDiscovery,
    getBleStatus,
    connect,
    disconnect,
    getDevConStaus,
    getDevServices,
    getDevChars,
    writeDevCharValue,
    readDevCharValue,
    onDevCharValueChange,
    offDevCharValueChange,
    enableDevCharNotify,
}